import os
import re
import sys


class Config(object):
    def __init__(self, config_file_path):
        self.config_file_path = config_file_path
        self.config_dir_path,self.config_file_name = os.path.split(config_file_path)
        self.config_dict = {}
        self.union_check_dict = {}
        self.config_template_dict = {
            'key_rules':{
                'regexp':False,
                'classify':False,
            },

            'template_keys':{
                'enable_sep': {
                    'type':"",
                    'is_bool':True,
                    'default': 1
                },
                'config_file_path':{
                    'type':"",
                    'default':self.config_file_path
                },

                'enable_file_name_regexp':{
                    'type':"",
                    'is_bool':True,
                    'default': 0
                },
                'classify:prefix':{
                    'type':"",
                    'is_bool':True,
                    'default': 1
                },
                'classify:suffix':{
                    'type':"",
                    'is_bool':True,
                    'default': 0
                },
                'dir_path':{
                    "type":"",
                    'less_check_value':True,
                    'default': os.path.abspath('.')
                },
                'sep':{
                    "type":"",
                    'less_check_value':True,
                    'default':"_",
                },
                'is_classify_file_type':{
                    'type':"",
                    'is_bool':True,
                    'default': 0

                },
                'is_exact':{
                    'type':"",
                    'is_bool':True,
                    'default': 1
                },
                'regexp:is_head_match':{
                    'type': "",
                    'is_bool': True,
                    'default': 0
                },
                'regexp:is_tail_match':{
                    'type':"",
                    'is_bool':True,
                    'default': 0
                },
                'regexp:is_line_match':{
                    'type':"",
                    'is_bool':True,
                    'default': 1
                },
                '_mapping':{
                    'type':"",
                    'is_bool':True,
                    'default': 0
                },
                'mapping.path':{
                    'type':"",
                    'default':"",
                    'required':True
                },
                'mapping.source':{
                    'type':set(),
                    'default':set(),
                    'required':True
                },
                'mapping.is_outer':{
                    'type': "",
                    'is_bool': True,
                    'default': 0
                }
            }
        }
    def parse_config(self):

        try:
            with open(self.config_file_path, 'r') as fp:
                for line in fp:
                    striped_line = line.strip()
                    if line.startswith('#') or not striped_line:
                        continue
                    key,value = striped_line.split('=')
                    key = key.strip()
                    value = value.strip()
                    value_list = value.split(',')
                    striped_value_list = [ no_striped_value.strip() for no_striped_value in value_list]
                    value = set(value_list) if len(set(striped_value_list)) > 1 else value
                    self.config_dict[key] = value
        except FileNotFoundError:
            print('[warning]: without configuration file, using default setting...')
            print('You can use att [-c] or [--configFile] command to create a default configuration file.')



        for key in self.config_dict.keys():
            if not self.check_key_exists(key):
                raise KeyError("key not exists")

        for template_key in self.config_template_dict['template_keys'].keys():

                if not self.read_and_check_value(template_key):
                    print(f"option error: option [{template_key}] value error or bad format. value is {self.config_dict[template_key]}")

        return self.config_dict

    def check_key_exists(self, key):
        if not self.config_template_dict['template_keys'].get(key, None):
            print(f"option error: can't found option [{key}] in {self.config_file_name}.")
            return False
        return True
    def read_and_check_value(self, key):

        factual_value = self.config_dict.get(key, None)

        if '.' in key:

            if self.union_check_dict.get(key.split('.')[0]) and self.config_template_dict['template_keys'][key].get('required'):
                print(f"option error: option [{key}] is required when [{'_' + key.split('.')[0]}] enable. in {self.config_file_name} ")
                return False

            if not self.union_check_dict.get(key.split('.')[0]):
                return True


        if not factual_value:
            self.config_dict[key] = self.config_template_dict['template_keys'][key]['default']
            return True


        if self.config_template_dict['template_keys'][key].get('less_check_value',False):
            return True


        expect_value_type = type(self.config_template_dict['template_keys'][key]['type'])
        expect_value_set = self.config_template_dict['template_keys'][key].get('value_set',None)

        if isinstance(factual_value, expect_value_type):

            if self.config_template_dict['template_keys'][key].get('is_bool',False):

                if factual_value not in ("0", "1"):

                    print(f"option's value error: [{key}] option require a single value 0 or 1 in {self.config_file_name}")
                    return False


                parsed_bool_value = int(factual_value)
                self.config_dict[key] = parsed_bool_value

                if key.startswith('_') and parsed_bool_value:
                    self.union_check_dict[key.split('_')[-1]] = True
                    return True

                check_key_type_list = key.split(':')
                if len(check_key_type_list) > 1:

                    if self.config_template_dict['key_rules'][check_key_type_list[0]] and parsed_bool_value:
                        self.config_template_dict['key_rules'][check_key_type_list[0]] = True
                        print(f"option error: you have selected a option in {check_key_type_list[0]}, it must be choose one. in {self.config_file_name}")
                        return False


                return True

            elif expect_value_type == str:
                if expect_value_set and factual_value not in expect_value_set:
                    value_set_format = '('
                    for expect_value in expect_value_set:
                        value_set_format += expect_value + ','

                    value_set_format += ')'
                    print(f"option error: text not a correct value you only selected in {value_set_format}")
                    return False
                return True


            elif expect_value_type == set:
                if self.config_template_dict['template_keys'][key]['is_regexp_check']:
                    regexp_str = self.config_template_dict[key]['regexp_str']
                    for value in factual_value:
                        if re.match(regexp_str, value):
                            print(f"option's value error: [{key}] option require a single value in {self.config_file_name}")
                            return False
                    return True

                for value in factual_value:
                    if value not in expect_value_set:
                        print("xxxxxx")
                        return False
                return True
        else:
            if expect_value_type == str:
                print(f"option's value error: [{key}] option require a single value in {self.config_file_name}")

            elif expect_value_type == set:
                print(f"option's value error: [{key}] option require a multiple value in {self.config_file_name}")









